//
// Created by wlk12 on 2023/3/23.
//

#include <iostream>
#include <memory>
#include <vector>

class A
{
public:
    A() noexcept
    {
        n = id++;
        std::cout << "Construct A: " << n << std::endl;
    }

    ~A() noexcept
    {
        std::cout << "Destruct ~A: " << n << std::endl;
        n = 0;
    }

    A(const A& a) noexcept
    {
        this->n = a.n;
        std::cout << "Copy Destruct A: " << n << std::endl;
    }

    A(A&& a) noexcept // 必须加上noexcept vector重新分配内存时才会使用移动构造
    {
        this->n = a.n;
        a.n *= -1;
        std::cout << "Move Destruct A: " << n << std::endl;
    }


    int n{};
    static int id;
};
int A::id = 0;

static int MyAllocID = 0;
template <typename T>
class MyAlloc {
public:
    // type definitions
    using value_type = T;
    // constructors
    // - nothing to do because the allocator has no state
    MyAlloc () noexcept {
        this->n = MyAllocID++;
        std::cout << "Construct MyAlloc: " << n << ",  Type:" << typeid(T).name() << std::endl;
    }

    MyAlloc (const MyAlloc<T>&) noexcept {
        this->n = MyAllocID++;
        std::cout << "Copy Construct MyAlloc: " << n << ",  Type:" << typeid(T).name() << std::endl;
    }

    // 用于Rebind，转换
    template <typename U>
    explicit MyAlloc (const MyAlloc<U>&) noexcept {
        // no state to copy
        this->n = MyAllocID++;
        std::cout << "Convert Construct MyAlloc: " << n << ",  Type T:" << typeid(T).name()
                << ",  Type U:" << typeid(U).name() << std::endl;
    }

    ~MyAlloc() noexcept
    {
        std::cout << "Destruct MyAlloc: " << n << ",  Type:" << typeid(T).name() << std::endl;
    }

    // allocate but don’t initialize num elements of type T
    T* allocate (std::size_t num) {
        // allocate memory with global new
        auto p = static_cast<T*>(::operator new(num*sizeof(T)));
        return p;
    }
    // deallocate storage p of deleted elements
    void deallocate (T* p, std::size_t num) {
        // deallocate memory with global delete
        ::operator delete(p);
    }

    int n{};
};
// return that all specializations of this allocator are interchangeable
template <typename T1, typename T2>
bool operator== (const MyAlloc<T1>&, const MyAlloc<T2>&) noexcept {
    return true;
}
template <typename T1, typename T2>
bool operator!= (const MyAlloc<T1>&, const MyAlloc<T2>&) noexcept {
    return false;
}


class MyAlloc2 {
public:

    using value_type = A;

    // 实际容器内部并不会直接使用MyAlloc2，容器内部都会通过Rebind从新获取分配器类型
    template <typename U> struct rebind { using other = std::allocator<U>; };

//    A* allocate (std::size_t num) {
//        return static_cast<A*>(::operator new(num*sizeof(A)));
//    }
//
//    void deallocate (A* p, std::size_t num) {
//        ::operator delete(p);
//    }
};


int main()
{
    {
        std::cout << "----Allocator-------" << std::endl;
        std::allocator<A> aa;
        auto p = aa.allocate(2);
        aa.construct(p);
        aa.destroy(p);
        aa.deallocate(p, 1);
    }

    {
        std::cout << "----vector MyAlloc------" << std::endl;
        std::vector<A, MyAlloc<A>> va;
        va.resize(2);
        va.emplace_back();
//        va.resize(6);
        auto&& al = va.get_allocator();
    }

    {
        std::cout << "----vector MyAlloc2--------" << std::endl;
        std::vector<A, MyAlloc2> va;
        va.resize(2);
    }

    return 0;
}